本篇笔记将介绍工具栏中的调用模块。这其中有两大模块,分别是外部调用和本地调用。外部调用可以用于任何适配器与外部/后端系统进行通信。而本地调用主要用于调用当前开发界面中的对象。
SAP CPI Palette Functions - 外部和本地调用
一、介绍
本篇笔记将介绍工具栏中的调用模块。这其中有两大模块,分别是外部调用和本地调用。外部调用可以用于任何适配器与外部/后端系统进行通信。而本地调用主要用于调用当前开发界面中的对象。
二、外部调用
1.介绍与分类
外部调用可以用于任何适配器与外部/后端系统进行通信。CPI提供了四种外部调用。
- 内容扩充器
- 轮询扩充
- 请求回复
- 发送
本片笔记主要介绍内容扩充器、请求回复和发送。

2.内容扩充器
(1)介绍
该对象可以将我们传入的有效负载和接收器系统响应的有效负载连接起来。例如我们通过OData API响应和我们调用这个IFlow时传入的有效负载组合在一起。
内容扩充器只有一个聚合的属性。但是该属性有两种选项。
- Combine:单纯的将传入的有效负载和接收器系统的响应连接起来。
- Enrich:允许我们根据 XML 中的关键元素组合两个有效负载,将两个单独的消息转换为单个增强的有效负载。您必须为扩充算法提供 4 个参数 – 原始(内容扩充器的传入有效负载)和查找消息(连接到内容扩充器的接收方响应)。

(2)示例 Combine
仅使用单独的内容扩充器是不行的,必须连接到接收器系统。我们创建一个如下图所示的IFlow。然后选择Aggregation Algorithm的属性为Combine。

OData的设置内容如下所示。


然后保存并部署这个IFlow。然后转到管理集成内容拿到调用的URL。

(3)测试 Combine
① 结果
使用下面的内容进行测试。通过一个XML转JSON的转换器后,将最后合并在一起的XML报文转换成JSON报文。

我们对刚刚的请求进行调试。可以看到各个不同步骤下的报文内容。
② HTTPS 的传入报文

③ 通过内容扩充器的报文

④ 返回的报文

⑤ OData Service报文
补充一个OData Service的报文。
1 | <Order_Details> |
(4)示例 Enrich
大部分的内容都不需要变更,只需要变更内容扩展器的属性,然后设置用于组合两个有效负载的参数。其实也就是用于进行匹配的层级和字段。OData Service的报文还是以上面的报文结构为示例,下面是调用该IFlow时传入的有效负载。
1 | <Orders> |
我们准备使用上面这个报文中Orders层级下面的Order层级下面的ProductID属性与OData Service中的Order_Details层级下面的Order_Detail层级下面的ProductID进行匹配。内容扩展器的配置如下所示。

完成之后请记得重新进行部署。待部署完成之后再进行后续的测试。
(5)测试 Enrich
使用CPI Helper插件中的Trace对接下来的报文进行追踪。然后到PostMan中使用上面的报文进行测试。

可以看到两段报文根据ProductID字段进行组合在一起了。但是有个注意事项是报文中的Order_Detail是一个JSON结构不是数组。如果要设置格式统一则可以在XML转JSON的转换器中按照下面的方式设置。

再次进行测试。

这里就不再笔记中记录Trace的结果截图了。有兴趣的可以自己尝试去看看。
3.请求回复
(1)介绍
与内容扩充器不同,请求回复不会将传入的有效负载与查找消息连接起来,而是仅将响应转发到下一个调色板函数。原始/源消息在请求回复步骤后将不再有效。请求回复本质上是同步的。

集成流步骤中的两个内容修正符的内容如下所示。都是一样的。

OData的设置内容与上面的相同,只不过有效负载的传入方向不一样。并且此时不管你怎么设置调用这个IFlow的传入报文在最后都会被OData Service的报文覆盖。使用下图所示的报文对上面的IFlow进行测试。

可以看到我们传入的报文被后面OData Service返回的报文内容覆盖掉了。但是这时候我们又需要在后面使用一开始传入的报文,这个时候我们就可以使用一个内容修正符先将传入的有效负载存储起来。如下所示。存储在Exchange Property中的内容不会被传递给源系统。

之后我在OData调用结束后的内容修正符2中将刚刚存储在Exchange Property中的有效负载放在Body中。

修改通过XML转换成JSON的有效负载中的Header和Body内容。

完成之后保存并重新对IFlow进行部署。再次使用相同的报文内容对IFlow进行测试。

4.发送
(1)介绍
使用此对象,只有与以下一种适配器类型结合使用才有意义(针对发送步骤和接收方之间的通道)。大多数情况下在IFlow中会使用Request reply (请求回复)。Send(发送)并不常使用。
- AS2 适配器
- FTP 适配器
- JMS 适配器:请求队列
- 邮件适配器
- SOAP SAP RM 适配器
- SFTP 适配器
- XI 适配器(服务质量“仅一次”)

三、本地调用
1.介绍
本地调用通常只会调用当前IFlow中的对象。如果将IFlow比作程序的话,本地调用就只会调用局部变量。

2.流程调用
(1)介绍
这个调用需要你的IFlow中存在本地集成流才可以使用。它可以在集成流中调用你在IFlow中定义的本地集成流对象。当你在集成流中调用对应的本地集成流对象时,该对象中的流程将被执行一次。
(2)定义本地集成流
我们参照下图定义一个IFlow对象。其中在本地集成流中添加一个内容修正符。修正符中为转换的JSON报文外层再套一层JSON结构。

(3)定义主集成流
在传入的报文起始添加一个XML转JSON的转换器,再加一个内容修正符。修正符中一样在报文的外层再加一个结构。

(4)调用本地集成流
添加一个流程调用步骤,然后设置其调用的本地集成流为我们上面创建好的本地集成对象。

(5)测试IFlow
保存并部署IFlow,然后使用从管理集成内容界面拿到端点信息后使用PostMan进行测试。

使用CPI Helper插件进行追踪验证也可以发现本地集成流被调用了。

3.循环流程调用
(1)介绍
如果要多次或基于条件执行本地集成流程,则可以使用循环流程调用。但是有一个注意事项,再一次请求中如果有一条数据不满足条件,那么循环就会终止,不管这条不满足条件的请求在报文的开头还是中间或是结尾。
相反,如果请求的报文中一致满足条件表达式中的条件则会一直循环,直到达到循环上限为止。
- Local Integration Process:本地集成流对象
- Expression Type:表达式类型。指定要在“条件表达式”字段中输入的表达式种类。
- XML:用于 XPath 表达式,例如://customerName = ‘Smith’。
- Non-XML:用于 Camel 简单表达式语言。${header.SenderId}指示 SenderId 标头字段;${in.body}指示传入消息的正文。
- Condition Expression:条件表达式,输入表达式以指定路由条件。只要条件为 true,即可执行循环处理。XML 条件示例:/bank_name/bank_id = ‘mybank’, //BankId = ‘ABC’;非 XML 条件示例:${header.SenderId} = ‘001’。
- Max. Numbers of Iterations:最大迭代次数。指定循环将执行的最大迭代次数。即使条件仍然满足,循环也将随之结束。
- Action when Max. Iterations Reached:达到最大迭代次数时的操作。
- End Loop:结束循环
- Throw Exception:抛出异常
(2)添加内容修正符
先在主流程中添加一个内容修正符,在Property页签中新增一个名为loopIndex的全局变量并设置一个默认值为1。

(3)修改本地集成流
在本地集成流中添加一个Groovy Script的脚本。这个脚本主要做的就是编辑上面内容修正符中定义在Property中的变量loopIndex。用来记录本地集成流被调用了几次。


添加完成脚本组件后,点击下图红框所示的按钮,编写脚本逻辑。

编写的内容如下所示。每次调用本地集成流时,使变量loopIndex后面拼接一个1。

1 | import com.sap.gateway.ip.core.customdev.util.Message; |
(4)设置循环流程调用
在主集成流中,在第一个内容修正符后面添加一个循环流程调用。并设置属性如下。

设置Condition Expression时,建议按照上面的方式设置。但是这样设置的层级只能到第二级。参考一会的调用报文。
设置Max. Numbers of Iterations为10,代表最大的调用次数为10次。
修改Action when Max. Iterations Reached为End Loop,代表达到最大的循环次数之后结束循环。
(5)设置结束时的内容修正符
在结束时,我们将发送进来的报文和前面定义的loopIndex变量的结果拼接在一起,用来查看本地集成流被调用的次数。

(6)测试IFlow
① 正向测试
将上面的IFlow保存并激活后,使用下面所示的报文进行测试。
1 | <arrey> |

可以看到末尾存在10个拼接起来的1。
② 反向测试
1 | <arrey> |

使用这个报文进行测试时可以看到末尾只有一个1,相当于本地集成流只调用了一次。
4.幂等流程调用
(1)介绍
执行流程调用步骤以检查传入消息是否已处理,然后跳过此消息的处理。主要用来处理重复请求的情况。
如果您只想执行一次订单,并且重试时不应处理该订单。在这种情况下,使用 Idempotent 进程调用将起作用。幂等进程调用检测订单或您在消息 ID 字段中提供的任何订单是否已成功处理,并将成功进程的状态存储在幂等存储库中。如果找到重复项,则消息将标记为重复项。如果您的接收器系统(例如第三方系统)无法正确处理重复消息,则可以从幂等进程调用中调用接收器系统。
- Local Integration Process:本地集成流程。选择要调用的预定义本地集成流程。
- Message ID:消息标识。使用 ${header.headername} 或 ${property.propertyname} 动态地从标头或属性中读取值。
- Skip Process Call for Duplicates:跳过重复流程调用。如果选中此选项,则当存在重复消息时,本地集成流程不会运行。如果取消选中此选项,则始终运行本地集成流程。使用以下 NON-XML 条件检查是否正在处理重复消息:“${property.CamelDuplicateMessage}=’true’”
(2)添加内容修正符
为了模拟重复调用的情况。我们在请求的开始添加一个内容修正符,并添加一个Hedar的headerFlag参数,设置其默认值为65534。如下图所示。

在Property参数中添加一个loopIndex的参数,然后再Message Body中将传入的报文填入。

(3)添加幂等流程调用

(4)本地集成流
本地集成流中还是和上面的一样。但是还是截个图。

1 | import com.sap.gateway.ip.core.customdev.util.Message; |
(5)末尾内容修正符
也和上面的一样。将传入的报文和记录本地集成流调用测试的变量组合在一起。

(6)测试IFlow
使用CPI Helper的Trace对接口进行调试。

然后对接口进行调用。

可以看到末尾有一个1。然后我们在使用插件中的记录进行查看。发现本地集成流被调用。

我们再次使用相同的内容对IFlow进行调用。可以发现末尾的1不见了。说明本地子流程没有被调用。

在使用插件的调试查看。发现本地集成流没有被调用。
